/*
 * Copyright (C) 2014 luke.
 * 
 * This file is part of Silvie.
 * 
 * Silvie is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Silvie is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Silvie.  If not, see <http://www.gnu.org/licenses/>.
 */

package silvie.resources;

import java.io.File;
import java.util.Arrays;
import java.util.function.Function;
import java.util.regex.Pattern;

import silvie.resources.chrmodel.CHRModel;
import silvie.resources.images.PAKBackgroundImage;
import silvie.resources.images.RAWImage;
import silvie.resources.sprite.SpriteContainer;
import silvie.resources.video.SMKVideo;

/**
 * Enumerated type for all supported Silver resource formats. Each format is
 * given a "factory" Function for instantiating the corresponding
 * AbstractResource specialization.
 * 
 * @author luke
 */
public enum ResourceFormat {
	// These formats are identified by file extension only
	// @formatter:off
	CHR(f -> new CHRModel(f), "(?i).*\\.chr"),
	SMK(f -> new SMKVideo(f), "(?i).*\\.smk"),
	PAK(f -> new PAKBackgroundImage(f), "(?i).*\\.pak"),
	SPR(f -> new SpriteContainer(f), "(?i).*\\.spr"),
	// The RAW format is either a .raw file or any file in levels/credits
	RAW(f -> new RAWImage(f), "(?i).*\\.raw", ".*/credit/[A-Z0-9]+");
	// @formatter:on

	private Pattern[] filepathPatterns;
	private Function<File, AbstractResource> factoryFunction;

	/**
	 * Private ResourceFormat constructor.
	 * 
	 * @param factoryFunction a Function that creates the appropriate
	 *        AbstractResource specialization for this format.
	 * @param filepathRegexes the regular expression(s) matching the file paths
	 *        associated with this format.
	 */
	private ResourceFormat(Function<File, AbstractResource> factoryFunction, String... filepathRegexes) {
		this.filepathPatterns = Arrays.stream(filepathRegexes).map(r -> Pattern.compile(r)).toArray(Pattern[]::new);
		this.factoryFunction = factoryFunction;
	}

	public Function<File, AbstractResource> getFactoryFunction() {
		return this.factoryFunction;
	}

	/**
	 * Tests {@code filepath} against all known formats and returns the
	 * corresponding ResourceFormat if a match is found.
	 * 
	 * @param filepath the filepath to test.
	 * @return the corresponding ResourceFormat, or null if no matching format
	 *         is found.
	 */
	public static ResourceFormat getFormat(String filepath) {
		for (ResourceFormat format : ResourceFormat.values()) {
			for (Pattern pattern : format.filepathPatterns) {
				if (pattern.matcher(filepath).matches()) {
					return format;
				}
			}
		}
		return null;
	}
}
